/* Copyright (c) 2010, David Kreuter. See LICENSE for more information */

#include "headers.h"

narc *read_narc(uint8 *buf, uint32 len){
	START(read_narc);
	narc *n=(narc*)malloc(sizeof(narc));n->num_files=0;

	MAGIC(0,NARC,read_narc);
	// 0x04 Magic number (always FE FF 00 01)
	CHECK_LEN(8,read_narc);
	// 0x0C Size of header (always 16)
	// 0x0E Number of sub-sections (always 3)

	uint32 btaf=0x10;
	MAGIC(btaf,BTAF,read_narc);
	// 0x14 12+8*num_files
	n->num_files=RL(btaf+0x8);
	DEBUG("%d files in NARC\n",n->num_files);
	n->file=(uint8**)calloc(sizeof(char*),n->num_files);
	n->size=(uint32*)calloc(sizeof(long ),n->num_files);
	int i;
	for(i=0;i<n->num_files;i++){
		n->file[i]=(uint8*)RL(btaf+0xC+8*i);
		n->size[i]=RL(btaf+0xC+8*i+4)-(uint32)n->file[i];
		// WARNING: Actually file[i] should contain the pointer to the
		// packed file but the first line writes the offset instead. The
		// gmif-reader fixes that. The second line reads the end not the
		// size.
	}

	uint32 btnf=btaf+0xC+8*n->num_files;
	MAGIC(btnf,BTNF,read_narc);
	if(RL(btnf+4)!=16){
		ERROR("Stop! This NARC has filenames and/or directories!\n");
		return 0;
	}
	// btnf+  8: always 4
	// btnf+0xC: always 0
	// btnf+0xE: always 1

	uint32 gmif=btnf+0x10;
	MAGIC(gmif,GMIF,read_narc);
	// btnf+0x14 Size of GMIF (irrelevant)
	if(RL(gmif+0x8)==0x4C5A3737){ // 0x4C5A3737 is the hex for LZ77
		ERROR("Stop! This NARC is compressed!\n");
		return 0;
	}
	for(i=0;i<n->num_files;i++){
		uint32 offset=((uint32)n->file[i])+gmif+0x8;
		n->file[i]=(uint8*)malloc(n->size[i]); // see comment above
		memcpy(n->file[i],buf+offset,n->size[i]);
	}

	END(read_narc,n);
	
	free_narc(n);
        return 0;
}


int write_narc(narc *n, uint8 *buf, uint32 len){
	START(write_narc);

	memcpy(buf,"NARC\xFE\xFF\x00\x01\x00\x00\x00\x00\x10\x00\x03\x00",16);

	uint32 btaf=0x10;
	memcpy(buf+btaf,"BTAF",4);
	RL(btaf+0x4)=12+8*n->num_files;
	RL(btaf+0x8)=n->num_files;
	int i;
	uint32 file_pos=0;
	for(i=0;i<n->num_files;i++){
		RL(btaf+0xC+i*8  )=file_pos;
		file_pos+=n->size[i];
		RL(btaf+0xC+i*8+4)=file_pos;
		file_pos=(file_pos+3)&~3; // Align to 4 bytes
	}

	uint32 btnf=btaf+0xC+8*n->num_files;
	memcpy(buf+btnf,"BTNF\x10\x00\x00\x00\x04\x00\x00\x00\x00\x00\x01\x00",16);

	uint32 gmif=btnf+0x10;
	memcpy(buf+gmif,"GMIF",4);
	file_pos=0x8;
	for(i=0;i<n->num_files;i++){
		memcpy(buf+(gmif+file_pos),n->file[i],n->size[i]);
		file_pos+=n->size[i];
		uint8 ff_fill=(4-(n->size[i]&3))%4;
		memcpy(buf+(gmif+file_pos),"\xFF\xFF\xFF\xFF",ff_fill);
		file_pos+=ff_fill; // Align to 4 bytes by padding with FFs
	}

	RL(gmif+0x4)=file_pos;
	RL(0x8)=gmif+file_pos;

	END(write_narc,1);

	return 0;
}

void save_file(narc *n, uint16 file_nr, uint8 *content, uint32 size){
	START(save_file);
	if(file_nr>=n->num_files){
		DEBUG("Extending NARC from %d entries to %d entries\n",
			n->num_files,file_nr+1);
		n->file=(uint8**)recalloc(n->file,sizeof(char*),file_nr+1);
		n->size=(uint32 *)recalloc(n->size,sizeof(long ),file_nr+1);
		while(n->num_files<file_nr+1){
			n->file[n->num_files]=0;
			n->size[n->num_files]=0;
			n->num_files++;
		}
	}
	if(n->file[file_nr])free(n->file[file_nr]);
	n->file[file_nr]=content;
	n->size[file_nr]=size;
	ENDV(save_file);
}

void free_narc(narc *n){
	START(free_narc);
	if(n){
		int i;
		for(i=0;i<n->num_files;i++)free(n->file[i]);
		if(n->file)free(n->file);
		if(n->size)free(n->size);
		free(n);
	}
	ENDV(free_narc);
}

uint32 size_narc(narc *n){
	START(size_narc);
	uint32 btaf=0x10;
	uint32 btnf=btaf+0xC+8*n->num_files;
	uint32 gmif=btnf+0x10;
	uint32 file_pos=0x8;
	for(uint16 i=0;i<n->num_files;i++)
		file_pos+=n->size[i]+(4-(n->size[i]&3))%4;
	END(size_narc,gmif+file_pos);
}
